﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE;
using ClassMetadataBrowser.Domain.Metadata;
using ClassMedataBrowser.Domain;

namespace ClassMetadataBrowser.Domain
{
	public abstract class MetadataObjectBase
	{
		#region class members

		private CodeElement _element;
		private INavigateToCodeElement _navigator;

		#endregion

		#region properties

		public CodeElement Element
		{
			get { return _element; }
		}

		public string ProjectName
		{
			get;
			set;
		}

		public int AttributesCount
		{
			get;
			protected set;
		}

		public string Name
		{
			get;
			set;
		}

		public bool IsPrivate
		{
			get;
			private set;
		}

		public bool IsProptected
		{
			get;
			private set;
		}

		public bool IsInternal
		{
			get;
			private set;
		}

		public MetadataObjectType Type
		{
			get;
			set;
		}

		public string ContainingFilePath
		{
			get;
			set;
		}

		#endregion

		protected void SetCodeElement(CodeElement element)
		{
			_element = element;
			CodeElementSet(element);
		}

		protected abstract void CodeElementSet(CodeElement element);

		public abstract void Accept(IMetadataVisitor visitor);

		protected void SetAccess(vsCMAccess access)
		{
			IsPrivate = access == vsCMAccess.vsCMAccessPrivate;
			IsInternal = access == vsCMAccess.vsCMAccessAssemblyOrFamily;
			IsProptected = access == vsCMAccess.vsCMAccessProjectOrProtected || access == vsCMAccess.vsCMAccessProtected;
		}

		public static MetadataObjectBase CreateCode(MetadataObjectType type, CodeElement codeElement, string name, INavigateToCodeElement navigator)
		{
			MetadataObjectBase obj = null;

			switch (type)
			{
				case MetadataObjectType.Class:
					obj = new ClassMetadata();
					break;
				case MetadataObjectType.Delegate:
					obj = new DelegateMetadata();
					break;
				case MetadataObjectType.Enum:
					obj = new EnumMetdata();
					break;
				case MetadataObjectType.Event:
					obj = new EventMetadata();
					break;
				case MetadataObjectType.Interface:
					obj = new InterfaceMetdata();
					break;
				case MetadataObjectType.Method:
					obj = new MethodMetadata();
					break;
				case MetadataObjectType.Property:
					obj = new PropertyMetadata();
					break;
				case MetadataObjectType.Struct:
					obj = new StructMetadata();
					break;
				case MetadataObjectType.Uknown:
					throw new ApplicationException("Uknown type is passed");
			}

			obj._navigator = navigator;
			obj.Name = name;
			obj.Type = type;
			obj.SetCodeElement(codeElement);

			if (codeElement.ProjectItem != null && codeElement.ProjectItem.ContainingProject != null)
				obj.ProjectName = codeElement.ProjectItem.ContainingProject.Name;

			return obj;
		}

		public void Navigate()
		{
			_navigator.Navigate(this);
		}
	}
}
